package handler

import (
	"fmt"
	"io"
	"mime/multipart"
	"react-router/model"
	"time"

	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm"
)

// FileValidator 文件验证接口
type FileValidator interface {
	ValidateFileSize(size int64) error
	ValidateFileType(contentType string, fileType string) error
}

// FileStorage 文件存储接口
type FileStorage interface {
	SaveFile(file *multipart.FileHeader, uuid string) (string, error)
	GenerateFilePath(uuid string, ext string) string
}

// UploadHandler 上传处理接口
type UploadHandler interface {
	HandleFileUpload(ctx *fiber.Ctx, fileType string) error
}

// 实现 FileValidator 接口
type DefaultFileValidator struct {
	maxFileSize      int64
	allowedImgTypes  map[string]bool
	allowedFileTypes map[string]bool
}

func NewFileValidator(maxSize int64) *DefaultFileValidator {
	validator := &DefaultFileValidator{
		maxFileSize:      maxSize,
		allowedImgTypes:  make(map[string]bool),
		allowedFileTypes: make(map[string]bool),
	}
	validator.initAllowedTypes()
	return validator
}

func (v *DefaultFileValidator) initAllowedTypes() {
	for _, fileType := range model.AllowedFileTypes {
		v.allowedFileTypes[fileType] = true
	}
}

func (v *DefaultFileValidator) ValidateFileSize(size int64) error {
	if size > v.maxFileSize {
		return fmt.Errorf("file size exceeds limit")
	}
	return nil
}

func (v *DefaultFileValidator) ValidateFileType(contentType, fileType string) error {
	if fileType == "image" && !v.allowedImgTypes[contentType] {
		return fmt.Errorf("unsupported image type")
	}
	if fileType == "file" && !v.allowedFileTypes[contentType] {
		return fmt.Errorf("unsupported file type")
	}
	return nil
}

// 修改 DefaultUploadHandler
type DefaultUploadHandler struct {
	validator   FileValidator
	repository  FileRepository
	maxFileSize int64
}

func NewUploadHandler(validator FileValidator, repository FileRepository, maxFileSize int64) *DefaultUploadHandler {
	return &DefaultUploadHandler{
		validator:   validator,
		repository:  repository,
		maxFileSize: maxFileSize,
	}
}

func (h *DefaultUploadHandler) HandleFileUpload(ctx *fiber.Ctx, fileType string) error {
	file, err := ctx.FormFile("file")
	if err != nil {
		return NewErrorResponse(ctx, model.ERROR_FILE_UPLOAD)
	}

	if err := h.validateFile(file, fileType); err != nil {
		return err
	}

	fileModel, err := h.processFile(file)
	if err != nil {
		return err
	}

	return NewSuccessResponse(ctx, fileModel)
}

func (h *DefaultUploadHandler) processFile(file *multipart.FileHeader) (*model.File, error) {
	hash, err := calculateFileHash(file)
	if err != nil {
		return nil, fmt.Errorf("hash calculation failed: %w", err)
	}

	existingFile, err := h.repository.FindByHash(hash)
	if err != nil {
		return nil, err
	}
	if existingFile != nil {
		return existingFile, nil
	}

	fileData, err := h.readFileData(file)
	if err != nil {
		return nil, err
	}

	fileModel := &model.File{
		FileName:    file.Filename,
		FileSize:    file.Size,
		ContentType: file.Header.Get("Content-Type"),
		Data:        fileData,
		Hash:        hash,
		Status:      0,
		UploadTime:  time.Now().Unix(),
	}

	if err := h.repository.Create(fileModel); err != nil {
		return nil, err
	}

	return fileModel, nil
}

func (h *DefaultUploadHandler) readFileData(file *multipart.FileHeader) ([]byte, error) {
	src, err := file.Open()
	if err != nil {
		return nil, err
	}
	defer src.Close()

	return io.ReadAll(src)
}

// 验证文件的辅助方法
func (h *DefaultUploadHandler) validateFile(file *multipart.FileHeader, fileType string) error {
	if err := h.validator.ValidateFileSize(file.Size); err != nil {
		return NewErrorResponse(nil, model.ERROR_FILE_TOO_LARGE)
	}

	contentType := file.Header.Get("Content-Type")
	if err := h.validator.ValidateFileType(contentType, fileType); err != nil {
		if fileType == "image" {
			return NewErrorResponse(nil, model.ERROR_IMAGE_FORMAT)
		}
		return NewErrorResponse(nil, model.ERROR_UNSUPPORTED_TYPE)
	}

	return nil
}

// 设置路由
func SetupUploadRoutes(app *fiber.App, db *gorm.DB) {
	db.AutoMigrate(&model.File{})

	validator := NewFileValidator(1 << 30) // 1GB
	repository := NewGormFileRepository(db)
	handler := NewUploadHandler(validator, repository, 1<<30)

	app.Post("/api/v1/upload/img", func(ctx *fiber.Ctx) error {
		return handler.HandleFileUpload(ctx, "image")
	})

	app.Post("/api/v1/upload/file", func(ctx *fiber.Ctx) error {
		return handler.HandleFileUpload(ctx, "file")
	})
}

// 响应处理函数
func NewErrorResponse(ctx *fiber.Ctx, code int) error {
	return ctx.Status(fiber.StatusBadRequest).JSON(model.NewErrorResponse(code))
}

func NewSuccessResponse(ctx *fiber.Ctx, data any) error {
	return ctx.Status(fiber.StatusOK).JSON(model.NewFileUploadSuccessResponse(data))
}
